#include "PVPSample.h"
#include <iostream>
#include <vector>
#include "stb_image.h"
PVPSample::PVPSample()
{
}

PVPSample::~PVPSample() {
	delete program;
}

void PVPSample::Init() {
	GLShader shaderVertex("../Assets/Shaders/GL02.vert");
	GLShader shaderGeometry("../Assets/Shaders/GL02.geom");
	GLShader shaderFragment("../Assets/Shaders/GL02.frag");
	program = new GLProgram(shaderVertex, shaderGeometry, shaderFragment);
	program->useProgram();

	kUniformBufferSize = sizeof(PerFrameData);

	glCreateBuffers(1, &perFrameDataBuffer);
	glNamedBufferStorage(perFrameDataBuffer, kUniformBufferSize, nullptr, GL_DYNAMIC_STORAGE_BIT);
	glBindBufferRange(GL_UNIFORM_BUFFER, 0, perFrameDataBuffer, 0, kUniformBufferSize);

	glEnable(GL_DEPTH_TEST);

	const aiScene* scene = aiImportFile("../Assets/Meshs/Woman/Woman.gltf", aiProcess_Triangulate);

	if (!scene || !scene->HasMeshes())
	{
		printf("Unable to load data/rubber_duck/scene.gltf\n");
		exit(255);
	}

	struct VertexData
	{
		glm::vec3 pos;
		glm::vec2 tc;
	};

	const aiMesh* mesh = scene->mMeshes[0];
	std::vector<VertexData> vertices;
	for (unsigned i = 0; i != mesh->mNumVertices; i++)
	{
		const aiVector3D v = mesh->mVertices[i];
		const aiVector3D t = mesh->mTextureCoords[0][i];
		vertices.push_back({ glm::vec3(v.x, v.y, v.z),glm::vec2(t.x, t.y) });
	}
	std::vector<unsigned int> indices;
	for (unsigned i = 0; i != mesh->mNumFaces; i++)
	{
		for (unsigned j = 0; j != 3; j++)
			indices.push_back(mesh->mFaces[i].mIndices[j]);
	}
	aiReleaseImport(scene);

	const size_t kSizeIndices = sizeof(unsigned int) * indices.size();
	const size_t kSizeVertices = sizeof(VertexData) * vertices.size();
	indiceSize = indices.size();
	// indices
	GLuint dataIndices;
	glCreateBuffers(1, &dataIndices);
	glNamedBufferStorage(dataIndices, kSizeIndices, indices.data(), 0);
	GLuint vao;
	glCreateVertexArrays(1, &vao);
	glBindVertexArray(vao);
	glVertexArrayElementBuffer(vao, dataIndices);

	// vertices
	GLuint dataVertices;
	glCreateBuffers(1, &dataVertices);
	glNamedBufferStorage(dataVertices, kSizeVertices, vertices.data(), 0);
	glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, dataVertices);

	// texture
	int w, h, comp;
	const uint8_t* img = stbi_load("../Assets/Meshs/Woman/Woman.png", &w, &h, &comp, 3);

	GLuint texture;
	glCreateTextures(GL_TEXTURE_2D, 1, &texture);
	glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, 0);
	glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTextureStorage2D(texture, 1, GL_RGB8, w, h);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTextureSubImage2D(texture, 0, 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, img);
	glBindTextures(0, 1, &texture);

	stbi_image_free((void*)img);
}

void PVPSample::Update(float deltatime)
{
}

void PVPSample::Render(float aspect) {
	const glm::mat4 scale = glm::scale(glm::mat4(1.0f),glm::vec3(0.4f));
	const glm::mat4 rotate = glm::rotate(scale, (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));
	const glm::mat4 m = glm::translate(rotate, glm::vec3(0.0f, 0.0f, 0.0f));
	const glm::mat4 p = glm::perspective(45.0f, aspect, 0.1f, 1000.0f);
	glm::mat4 v = glm::lookAt(glm::vec3(0.0,2.0,5.0),glm::vec3(0.0f),glm::vec3(0.0,1.0,0.0));
	const PerFrameData perFrameData = { p * v * m };
	glNamedBufferSubData(perFrameDataBuffer, 0, kUniformBufferSize, &perFrameData);
	glDrawElements(GL_TRIANGLES, static_cast<unsigned>(indiceSize), GL_UNSIGNED_INT, nullptr);
}

void PVPSample::OnGUI()
{
}

void PVPSample::ShutDown() {
	glDisable(GL_DEPTH_TEST);
}
